<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SHX Font Viewer</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        .container {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .file-input {
            padding: 20px;
            border: 2px dashed #ccc;
            border-radius: 4px;
            text-align: center;
        }
        .characters-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
            gap: 10px;
            padding: 20px;
        }
        .character-cell {
            border: 1px solid #ccc;
            padding: 10px;
            text-align: center;
            border-radius: 4px;
            cursor: pointer;
            transition: transform 0.1s ease-in-out;
            height: 140px;
            display: flex;
            flex-direction: column;
        }
        .character-cell:hover {
            transform: scale(1.02);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
        .character-svg {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 0; /* allow flex child to shrink */
        }

        .character-svg svg {
            width: 100%;
            height: 100%;
        }
        .character-info {
            font-size: 12px;
            color: #666;
            margin-top: 5px;
        }
        .font-info {
            background-color: #f5f5f5;
            padding: 20px;
            border-radius: 4px;
        }
        .font-info h2 {
            margin-top: 0;
            margin-bottom: 15px;
        }
        .font-info-grid {
            display: grid;
            grid-template-columns: auto 1fr;
            gap: 8px;
        }
        .font-info-label {
            font-weight: bold;
            color: #333;
        }
        .font-info-value {
            color: #666;
        }
        .mode-selector {
            display: flex;
            margin-bottom: 10px;
            border-bottom: 1px solid #ccc;
        }
        .mode-tab {
            padding: 10px 20px;
            cursor: pointer;
            border: 1px solid transparent;
            border-bottom: none;
            margin-bottom: -1px;
        }
        .mode-tab.active {
            background-color: #fff;
            border-color: #ccc;
            border-bottom-color: #fff;
        }
        .mode-content {
            display: none;
        }
        .mode-content.active {
            display: block;
        }
        .font-select {
            width: 100%;
            padding: 10px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        .search-container {
            margin: 10px 0;
            display: none;
            align-items: center;
            position: relative;
        }
        .search-input {
            flex: 1;
            padding: 10px;
            padding-right: 30px;  /* Space for the clear button */
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 14px;
        }
        .search-clear {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            background: none;
            border: none;
            cursor: pointer;
            padding: 0;
            font-size: 18px;
            color: #999;
            display: none;
        }
        .search-clear:hover {
            color: #666;
        }
        .format-toggle {
            display: none;  /* Hide by default */
            align-items: center;
            gap: 10px;
            margin: 5px 0;
        }
        .format-toggle label {
            cursor: pointer;
            user-select: none;
        }
        .format-toggle input[type="checkbox"] {
            margin: 0;
        }
        .loading {
            display: none;
            text-align: center;
            padding: 20px;
        }

        /* Modal styles */
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 1000;
            justify-content: center;
            align-items: center;
        }

        .modal-content {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            max-width: 90%;
            max-height: 90%;
            position: relative;
        }

        .modal-close {
            position: absolute;
            right: 10px;
            top: 10px;
            font-size: 24px;
            cursor: pointer;
            background: none;
            border: none;
            padding: 5px;
        }

        .modal-close:hover {
            color: #666;
        }

        .modal svg {
            width: 500px;
            height: 500px;
        }

        .modal-character-info {
            text-align: center;
            margin-top: 10px;
            font-size: 16px;
            color: #333;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>SHX Font Viewer</h1>
        
        <div class="mode-selector">
            <div class="mode-tab active" data-mode="local">Local Font File</div>
            <div class="mode-tab" data-mode="remote">Remote Font Library</div>
        </div>

        <div id="localMode" class="mode-content active">
            <div class="file-input">
                <input type="file" id="shxFile" accept=".shx" />
                <p>Select an SHX font file to view its characters</p>
            </div>
        </div>

        <div id="remoteMode" class="mode-content">
            <select id="remoteFontSelect" class="font-select">
                <option value="">Select a font from the library...</option>
            </select>
        </div>

        <div id="loading" class="loading">
            Loading font data...
        </div>

        <div id="fontInfo" class="font-info" style="display: none;">
            <h2>Font Information</h2>
            <div class="font-info-grid">
                <div class="font-info-label">Font Type:</div>
                <div id="fontType" class="font-info-value"></div>
                <div class="font-info-label">File Version:</div>
                <div id="fileVersion" class="font-info-value"></div>
                <div class="font-info-label">Number of Characters:</div>
                <div id="charCount" class="font-info-value"></div>
            </div>
        </div>
        
        <div class="search-container">
            <input type="text" id="codeSearch" class="search-input" placeholder="Search by code (e.g. 65 for 'A' or 0x41)" />
            <button type="button" id="searchClear" class="search-clear" aria-label="Clear search">&times;</button>
        </div>

        <div class="format-toggle">
            <input type="checkbox" id="formatToggle">
            <label for="formatToggle">Show codes in hexadecimal format</label>
        </div>

        <div id="charactersGrid" class="characters-grid"></div>
    </div>

    <!-- Modal for larger shape display -->
    <div id="shapeModal" class="modal">
        <div class="modal-content">
            <button class="modal-close">&times;</button>
            <div id="modalShape"></div>
            <div id="modalCharacterInfo" class="modal-character-info"></div>
        </div>
    </div>

    <script type="module">
        import { ShxFont, ShxFontType } from './dist/index.es.js';

        class ShxFontViewer {
            constructor() {
                this.fileInput = document.getElementById('shxFile');
                this.grid = document.getElementById('charactersGrid');
                this.fontInfoDiv = document.getElementById('fontInfo');
                this.remoteFontSelect = document.getElementById('remoteFontSelect');
                this.loadingDiv = document.getElementById('loading');
                this.codeSearch = document.getElementById('codeSearch');
                this.searchClear = document.getElementById('searchClear');
                this.searchContainer = document.querySelector('.search-container');
                this.formatToggle = document.getElementById('formatToggle');
                this.formatToggleContainer = document.querySelector('.format-toggle');
                this.modal = document.getElementById('shapeModal');
                this.modalClose = document.querySelector('.modal-close');
                this.modalShape = document.getElementById('modalShape');
                this.modalCharacterInfo = document.getElementById('modalCharacterInfo');
                this.font = null;
                const baseUrl = 'https://mlightcad.gitlab.io/cad-data/';
                this.fontBaseUrl = baseUrl + 'fonts/';
                this.fontLibraryUrl = this.fontBaseUrl + 'fonts.json';
                this.allCharacterCells = new Map(); // Store all character cells

                this.init();
            }

            init() {
                this.fileInput.addEventListener('change', this.handleFileSelect.bind(this));
                this.remoteFontSelect.addEventListener('change', this.handleRemoteFontSelect.bind(this));
                this.codeSearch.addEventListener('input', this.handleSearch.bind(this));
                this.codeSearch.addEventListener('input', this.toggleClearButton.bind(this));
                this.searchClear.addEventListener('click', this.clearSearch.bind(this));
                this.formatToggle.addEventListener('change', () => this.updateCodeFormat());
                this.initModeTabs();
                this.initModal();
                this.loadFontLibrary();
            }

            initModeTabs() {
                const tabs = document.querySelectorAll('.mode-tab');
                tabs.forEach(tab => {
                    tab.addEventListener('click', () => {
                        // Remove active class from all tabs and contents
                        tabs.forEach(t => t.classList.remove('active'));
                        document.querySelectorAll('.mode-content').forEach(c => c.classList.remove('active'));
                        
                        // Add active class to clicked tab and corresponding content
                        tab.classList.add('active');
                        document.getElementById(tab.dataset.mode + 'Mode').classList.add('active');
                        
                        // Clear previous display
                        this.clearDisplay();
                    });
                });
            }

            clearDisplay() {
                this.grid.innerHTML = '';
                this.fontInfoDiv.style.display = 'none';
                this.searchContainer.style.display = 'none';
                this.formatToggleContainer.style.display = 'none';
                this.font = null;
                this.allCharacterCells.clear();
                this.codeSearch.value = '';
            }

            async loadFontLibrary() {
                try {
                    const response = await fetch(this.fontLibraryUrl);
                    if (!response.ok) throw new Error('Failed to load font library');
                    const fonts = await response.json();
                    
                    // Clear existing options except the first one
                    this.remoteFontSelect.innerHTML = '<option value="">Select a font from the library...</option>';
                    
                    // Filter and add only SHX font options
                    fonts
                        .filter(font => font.type === 'shx')
                        .forEach(font => {
                            const option = document.createElement('option');
                            option.value = font.file;
                            option.textContent = font.name;
                            this.remoteFontSelect.appendChild(option);
                        });

                    if (this.remoteFontSelect.options.length === 1) {
                        // If no SHX fonts were found
                        const option = document.createElement('option');
                        option.disabled = true;
                        option.textContent = 'No SHX fonts available';
                        this.remoteFontSelect.appendChild(option);
                    }
                } catch (error) {
                    console.error('Error loading font library:', error);
                    alert('Error loading font library');
                }
            }

            async handleRemoteFontSelect(event) {
                const fontFile = event.target.value;
                if (!fontFile) return;

                this.loadingDiv.style.display = 'block';
                this.clearDisplay();

                try {
                    const response = await fetch(this.fontBaseUrl + fontFile);
                    if (!response.ok) throw new Error('Failed to load font file');
                    const arrayBuffer = await response.arrayBuffer();
                    this.font = new ShxFont(arrayBuffer);
                    this.displayFontInfo();
                    this.displayCharacters();
                } catch (error) {
                    console.error('Error loading remote font:', error);
                    alert('Error loading remote font file');
                } finally {
                    this.loadingDiv.style.display = 'none';
                }
            }

            async handleFileSelect(event) {
                const file = event.target.files[0];
                if (!file) return;

                this.loadingDiv.style.display = 'block';
                this.clearDisplay();

                try {
                    const arrayBuffer = await file.arrayBuffer();
                    this.font = new ShxFont(arrayBuffer);
                    this.displayFontInfo();
                    this.displayCharacters();
                } catch (error) {
                    console.error('Error loading font:', error);
                    alert('Error loading font file');
                } finally {
                    this.loadingDiv.style.display = 'none';
                }
            }

            displayFontInfo() {
                const fontData = this.font.fontData;
                const header = fontData.header;
                const content = fontData.content;

                // Show the font info section, search container, and format toggle
                this.fontInfoDiv.style.display = 'block';
                this.searchContainer.style.display = 'flex';
                this.formatToggleContainer.style.display = 'flex';

                // Update font information
                document.getElementById('fontType').textContent = header.fontType;
                document.getElementById('fileVersion').textContent = header.fileVersion;
                document.getElementById('charCount').textContent = Object.keys(content.data).length;
            }

            createCharacterCell(code, shape) {
                const cell = document.createElement('div');
                cell.className = 'character-cell';

                const svgString = shape.toSVG({
                    isAutoFit: true
                });
                
                // Create a temporary div to parse the SVG string
                const tempDiv = document.createElement('div');
                tempDiv.innerHTML = svgString;
                const svg = tempDiv.querySelector('svg');
                
                // Wrap SVG into a fixed-height flex container for consistent cell height
                const svgWrap = document.createElement('div');
                svgWrap.className = 'character-svg';
                svgWrap.appendChild(svg);
                cell.appendChild(svgWrap);

                const info = document.createElement('div');
                info.className = 'character-info';
                info.dataset.code = code;
                this.updateCellFormat(info, code);
                cell.appendChild(info);

                // Add click handler to show modal
                cell.addEventListener('click', () => this.showModal(code, shape));

                return cell;
            }

            updateCellFormat(infoElement, code) {
                const numCode = parseInt(code);
                infoElement.textContent = this.formatToggle.checked ? 
                    `Code: 0x${numCode.toString(16).toUpperCase()}` :
                    `Code: ${code}`;
            }

            updateCodeFormat() {
                this.allCharacterCells.forEach((cell, code) => {
                    const info = cell.querySelector('.character-info');
                    this.updateCellFormat(info, code);
                });
            }

            displayCharacters() {
                this.grid.innerHTML = '';
                this.allCharacterCells.clear();
                const fontData = this.font.fontData;

                Object.entries(fontData.content.data).forEach(([code, data]) => {
                    const shape = this.font.getCharShape(parseInt(code), 12);
                    if (shape) {
                        const cell = this.createCharacterCell(code, shape);
                        this.allCharacterCells.set(code, cell);
                        this.grid.appendChild(cell);
                    }
                });
            }

            handleSearch(event) {
                const searchValue = event.target.value.trim();
                const isBigFont = this.font.fontData.header.fontType === ShxFontType.BIGFONT;
                
                this.allCharacterCells.forEach((cell, code) => {
                    if (searchValue === '') {
                        cell.style.display = ''; // Show all when search is empty
                    } else {
                        let searchCode;
                        if (searchValue.toLowerCase().startsWith('0x')) {
                            // Handle hexadecimal input
                            searchCode = parseInt(searchValue, 16).toString();
                        } else {
                            // Handle decimal input
                            searchCode = parseInt(searchValue).toString();
                        }

                        if (!isNaN(parseInt(searchCode))) {
                            cell.style.display = code === searchCode ? '' : 'none';
                        } else if (!isBigFont) {
                            // For regular fonts, convert to Unicode
                            const charCode = searchValue.charCodeAt(0);
                            cell.style.display = code === charCode.toString() ? '' : 'none';
                        } else {
                            cell.style.display = 'none';
                        }
                    }
                });
            }

            toggleClearButton() {
                this.searchClear.style.display = this.codeSearch.value ? 'block' : 'none';
            }

            clearSearch() {
                this.codeSearch.value = '';
                this.searchClear.style.display = 'none';
                this.handleSearch({ target: this.codeSearch });
            }

            initModal() {
                // Close modal when clicking the close button
                this.modalClose.addEventListener('click', () => {
                    this.modal.style.display = 'none';
                });

                // Close modal when clicking outside the modal content
                this.modal.addEventListener('click', (e) => {
                    if (e.target === this.modal) {
                        this.modal.style.display = 'none';
                    }
                });

                // Close modal with Escape key
                document.addEventListener('keydown', (e) => {
                    if (e.key === 'Escape' && this.modal.style.display === 'flex') {
                        this.modal.style.display = 'none';
                    }
                });
            }

            showModal(code, shape) {
                this.modalShape.innerHTML = '';

                // Get SVG string with auto-fit enabled
                const svgString = shape.toSVG({
                    isAutoFit: true
                });
                
                // Create a temporary div to parse the SVG string
                const tempDiv = document.createElement('div');
                tempDiv.innerHTML = svgString;
                const svg = tempDiv.querySelector('svg');
                
                this.modalShape.appendChild(svg);
                
                // Update modal character info
                const numCode = parseInt(code);
                this.modalCharacterInfo.textContent = this.formatToggle.checked ? 
                    `Character Code: 0x${numCode.toString(16).toUpperCase()}` :
                    `Character Code: ${code}`;

                // Show modal
                this.modal.style.display = 'flex';
            }
        }

        // Initialize the viewer
        new ShxFontViewer();
    </script>
</body>
</html> 